import {http} from "../../modules/plain-design/http";
import {$dialog, Form, FormInput, FormItem, iValidatorParam, Select, SelectOption} from "plain-design";
import {defer} from "@peryl/utils/defer";
import {computed, designComponent, getComponentCls, PropType, reactive, useClassCache, useModel, useRefs} from "@peryl/react-compose";
import {deepcopy} from "@peryl/utils/deepcopy";
import './entity-code-selector.scss';

export const EntityListUtils = (() => {

  /*查询所有的实体数据*/
  const getAllEntities = async (): Promise<iEntity[]> => {
    const resp = await http.post<{ list: iEntity[] }>('/entity/list', { all: true });
    return [
      ...BasicEntities,
      ...resp.list,
    ];
  };

  /*编辑实体，打开抽屉表单*/
  const openEntityEditor = (
    data:
      { entity?: Partial<iEntity>, isCreate: true, parseEntities: iParseEntity[] } |
      { entity: iEntity, isCreate?: false, parseEntities: iParseEntity[] }
  ): Promise<iEntity> => {
    const dfd = defer<iEntity>();
    const { refs, onRef } = useRefs({ entityForm: EntityForm }, { reactive: false });
    $dialog({
      position: 'right',
      confirmButton: true,
      cancelButton: true,
      handleConfirm: async () => {
        await refs.entityForm!.refs.form!.validate();
        dfd.resolve(refs.entityForm!.state.formData as iEntity);
      },
      handleCancel: () => {dfd.reject('cancel');},
      render: () => (
        <EntityForm ref={onRef.entityForm} initialEntity={data.entity} isCreate={!!data.isCreate} siblingEntities={data.parseEntities}/>
      )
    });
    return dfd.promise;
  };

  /*打开编辑抽屉表单，编辑创建一个实体*/
  const createEntity = (data: { entity?: Partial<iEntity>, parseEntities: iParseEntity[] }) => {
    return openEntityEditor({ ...data, isCreate: true });
  };

  /*打开编辑抽屉表单，编辑更新一个实体*/
  const editEntity = (data: { entity: iEntity, parseEntities: iParseEntity[] }) => {
    return openEntityEditor({ ...data, isCreate: false });
  };

  /*调用接口删除实体*/
  const requestDelete = async (entityId: string) => {
    await http.post('/entity/delete', { id: entityId });
  };

  /*调用接口新建实体*/
  const requestInsert = async (entity: Partial<iEntity>): Promise<iEntity> => {
    const resp = await http.post<{ result: iEntity }>('/entity/insert', { row: entity });
    return resp.result;
  };

  /*调用接口更新实体*/
  const requestUpdate = async (entities: iEntity[]): Promise<iEntity[]> => {
    const resp = await http.post<{ result: iEntity[] }>('/entity/batchUpdate', { rows: entities });
    return resp.result;
  };

  /*将实体entity转化为iParseEntity*/
  const parseEntity = (() => {
    let generalityCache = {} as Record<string, iEntityGeneralityItem[]>;
    let fieldCache = {} as Record<string, iEntityFieldItem[]>;
    return (entity: iEntity): iParseEntity => {
      return {
        id: entity.id,
        code: entity.code,
        title: entity.title,
        seq: entity.seq,
        isBasic: !!entity.isBasic,
        isInternal: !!entity.isInternal,
        generalityConfig: (() => {
          if (!entity.generalityConfigJson) {return [];}
          let cache = generalityCache[entity.generalityConfigJson];
          if (!cache) {cache = generalityCache[entity.generalityConfigJson] = JSON.parse(entity.generalityConfigJson);}
          return cache;
        })(),
        fieldConfig: (() => {
          if (!entity.fieldConfigJson) {return [];}
          let cache = fieldCache[entity.fieldConfigJson];
          if (!cache) {cache = fieldCache[entity.fieldConfigJson] = JSON.parse(entity.fieldConfigJson);}
          return cache;
        })()
      };
    };
  })();

  /*将 iParseEntity转化为iEntity*/
  const reverseParseEntity = (parseEntity: iParseEntity): iEntity => {
    return {
      id: parseEntity.id,
      title: parseEntity.title,
      code: parseEntity.code,
      seq: parseEntity.seq,
      generalityConfigJson: JSON.stringify(parseEntity.generalityConfig),
      fieldConfigJson: JSON.stringify(parseEntity.fieldConfig),
    };
  };

  /**
   * 打开泛型编辑表单抽屉
   * @author  韦胜健
   * @date    2024.9.22 15:59
   */
  const openGeneralityItemEditor = (
    data:
      { generalityItem?: Partial<iEntityGeneralityItem>, isCreate: true, parseEntity: iParseEntity } |
      { generalityItem: iEntityGeneralityItem, isCreate?: false, parseEntity: iParseEntity }
  ): Promise<iEntityGeneralityItem> => {
    const dfd = defer<iEntityGeneralityItem>();
    const { refs, onRef } = useRefs({ generalityForm: GeneralityForm }, { reactive: false });
    $dialog({
      position: 'right',
      confirmButton: true,
      cancelButton: true,
      handleConfirm: async () => {
        await refs.generalityForm!.refs.form!.validate();
        dfd.resolve(refs.generalityForm!.state.formData as any);
      },
      handleCancel: () => {dfd.reject('cancel');},
      render: () => (
        <GeneralityForm initialGeneralityItem={data.generalityItem} isCreate={!!data.isCreate} ref={onRef.generalityForm} parseEntity={data.parseEntity}/>
      )
    });
    return dfd.promise;
  };

  /*打开编辑抽屉表单，编辑创建一个实体*/
  const createGeneralityItem = (data: { generalityItem?: Partial<iEntityGeneralityItem>, parseEntity: iParseEntity }) => {
    return openGeneralityItemEditor({ ...data, isCreate: true });
  };

  /*打开编辑抽屉表单，编辑更新一个实体*/
  const editGeneralityItem = (data: { generalityItem: iEntityGeneralityItem, parseEntity: iParseEntity }) => {
    return openGeneralityItemEditor({ ...data, isCreate: false });
  };

  /**
   * 打开字段编辑表单抽屉
   * @author  韦胜健
   * @date    2024.9.22 15:59
   */
  const openFieldItemEditor = (
    data:
      { fieldItem?: Partial<iEntityFieldItem>, isCreate: true, parseEntities: iParseEntity[], parseEntity: iParseEntity } |
      { fieldItem: iEntityFieldItem, isCreate?: false, parseEntities: iParseEntity[], parseEntity: iParseEntity }
  ): Promise<iEntityFieldItem> => {
    const dfd = defer<iEntityFieldItem>();
    const { refs, onRef } = useRefs({ fieldForm: FieldForm }, { reactive: false });
    $dialog({
      position: 'right',
      confirmButton: true,
      cancelButton: true,
      handleConfirm: async () => {
        await refs.fieldForm!.refs.form!.validate();
        dfd.resolve(refs.fieldForm!.state.formData as any);
      },
      handleCancel: () => {dfd.reject('cancel');},
      render: () => (
        <FieldForm initialFieldItem={data.fieldItem} isCreate={!!data.isCreate} ref={onRef.fieldForm} parseEntities={data.parseEntities} parseEntity={data.parseEntity}/>
      )
    });
    return dfd.promise;
  };

  /*打开字段抽屉表单，编辑创建一个实体*/
  const createFieldItem = (data: { fieldItem?: Partial<iEntityFieldItem>, parseEntities: iParseEntity[], parseEntity: iParseEntity }) => {
    return openFieldItemEditor({ ...data, isCreate: true });
  };

  /*打开字段抽屉表单，编辑更新一个实体*/
  const editFieldItem = (data: { fieldItem: iEntityFieldItem, parseEntities: iParseEntity[], parseEntity: iParseEntity }) => {
    return openFieldItemEditor({ ...data, isCreate: false });
  };

  const getGeneralityEntityName = (entityCode: iEntityFieldItem['entityCode'], parseEntities: iParseEntity[]): string => {
    const secName = parseEntities.find(i => i.code === entityCode.sec)?.code || 'Unknown';
    let generalityName = !entityCode.gcs ? '' : Object.values(entityCode.gcs).map(i => !i ? undefined : getGeneralityEntityName(i, parseEntities)).filter(Boolean).join(',');
    if (!!generalityName) {generalityName = `<${generalityName}>`;}
    return `${secName}${generalityName}`;
  };

  return {
    getAllEntities,
    createEntity,
    editEntity,
    requestInsert,
    requestUpdate,
    parseEntity,
    reverseParseEntity,
    requestDelete,
    createGeneralityItem,
    editGeneralityItem,
    openFieldItemEditor,
    createFieldItem,
    editFieldItem,
    getGeneralityEntityName,
  };
})();

/*实体对象类型*/
export interface iEntity {
  /*实体类型的唯一标识*/
  id: string,
  /*实体类型的显示名称*/
  title: string,
  /*实体类型的编码*/
  code: string,
  /*实体类型的显示顺序*/
  seq: number,
  /*
  * 实体类型是否为基础数据类型，如字符串、数字、布尔值、日期、日期时间等等，为基础数据类型；
  * 目前来说isBasic在运行阶段没有用到，只有在系统中编辑类型时，用于在计算cascadeData级联数据的时候用来判断不生成子节点数据
  * 也就是（src/pages/data/entity-list-page.tsx:265）这里用到
  */
  isBasic?: boolean,
  /*
  * 实体类型是否为内置类型，如数组、接口为内置类型；此外，所有isBasic：true的基础类型也是内置类型
  * 目前来说isInternal在运行阶段没有用到，只有在系统中编辑类型时，用于控制内置类型的不可编辑、不可排序等控制功能；
  */
  isInternal?: boolean,
  /*实体类型旗下泛型类型配置*/
  generalityConfigJson?: string,
  /*实体类型旗下的字段类型配置*/
  fieldConfigJson?: string,
}

/**
 * 解析实体类型之后得到的结果实体类型
 * @author  韦胜健
 * @date    2025/5/17 10:18
 */
export interface iParseEntity {
  id: string,
  title: string,
  code: string,
  seq: number,
  isBasic: boolean,
  isInternal: boolean,
  generalityConfig: iEntityGeneralityItem[],
  fieldConfig: iEntityFieldItem[],
}

/*泛型类型*/
export interface iEntityGeneralityItem {
  title: string,
  code: string
}

/*字段类型*/
export interface iEntityFieldItem {
  title: string,
  code: string,
  entityCode: iBindingGeneralityEntityCode,
}

export interface iBindingGeneralityEntityCode {
  sec: string,                                                       /*自身实体类型编码*/
  gcs?: Record<string, iBindingGeneralityEntityCode | undefined>     /*使用的泛型实体类型编码*/
}

/**
 * 实体类型编辑表单
 * @author  韦胜健
 * @date    2025/5/17 10:19
 */
const EntityForm = designComponent({
  name: 'entity-form',
  props: {
    initialEntity: { type: Object as PropType<Partial<iEntity>> },
    isCreate: { type: Boolean, required: true },
    siblingEntities: { type: Array as PropType<iParseEntity[]>, required: true },
  },
  setup({ props }) {

    const { refs, onRef } = useRefs({ form: Form });

    const state = reactive({
      formData: deepcopy(props.initialEntity || {})
    });

    const handler = {
      validator: !props.isCreate ? undefined : ({ value }: iValidatorParam) => {
        if (props.siblingEntities.find(i => i.code == value)) {
          return '标识唯一性冲突！';
        }
      },
    };

    return {
      refer: {
        refs,
        state,
      },
      render: () => (
        <Form ref={onRef.form} validateMessagePosition="bottom-right">
          <FormInput label="实体标题" required v-model={state.formData.title}/>
          <FormInput label="实体标识" required v-model={state.formData.code} disabled={!props.isCreate} validator={handler.validator}/>
        </Form>
      )
    };
  },
});

/**
 * 泛型类型编辑表单
 * @author  韦胜健
 * @date    2025/5/17 10:19
 */
const GeneralityForm = designComponent({
  name: 'generality-form',
  props: {
    initialGeneralityItem: { type: Object as PropType<Partial<iEntityGeneralityItem>> },
    isCreate: { type: Boolean, required: true },
    parseEntity: { type: Object as PropType<iParseEntity>, required: true }
  },
  setup({ props }) {

    const { refs, onRef } = useRefs({ form: Form });

    const state = reactive({
      formData: deepcopy(props.initialGeneralityItem || {})
    });

    const handler = {
      validator: !props.isCreate ? undefined : ({ value }: iValidatorParam) => {
        if (props.parseEntity.generalityConfig.find(i => i.code == value)) {
          return '泛型标识唯一性冲突';
        }
      },
    };

    return {
      refer: {
        refs,
        state,
      },
      render: () => (
        <Form ref={onRef.form} validateMessagePosition="bottom-right">
          <FormInput label={"泛型名称"} v-model={state.formData.title} required/>
          <FormInput label={"泛型标识"} v-model={state.formData.code} required disabled={!props.isCreate} validator={handler.validator}/>
        </Form>
      )
    };
  },
});

/**
 * 字段编辑表单
 * @author  韦胜健
 * @date    2025/5/17 10:19
 */
const FieldForm = designComponent({
  name: 'field-form',
  props: {
    initialFieldItem: { type: Object as PropType<Partial<iEntityFieldItem>> },
    isCreate: { type: Boolean, required: true },
    parseEntities: { type: Array as PropType<iParseEntity[]>, required: true },
    parseEntity: { type: Object as PropType<iParseEntity>, required: true }
  },
  setup({ props }) {

    const { refs, onRef } = useRefs({ form: Form });

    const state = reactive({
      formData: deepcopy(props.initialFieldItem || {})
    });

    const handler = {
      validator: !props.isCreate ? undefined : ({ value }: iValidatorParam) => {
        if (props.parseEntity.fieldConfig.find(i => i.code == value)) {
          return '字段标识唯一性冲突';
        }
      },
    };

    return {
      refer: {
        refs,
        state,
      },
      render: () => (
        <Form ref={onRef.form} validateMessagePosition="bottom-right">
          <FormInput label={"字段名称"} v-model={state.formData.title} required/>
          <FormInput label={"字段标识"} v-model={state.formData.code} required disabled={!props.isCreate} validator={handler.validator}/>
          <FormItem label={"字段类型"}>
            <EntityCodeSelector label={"字段类型"} hideLabel v-model={state.formData.entityCode} parseEntities={props.parseEntities}/>
          </FormItem>
        </Form>
      )
    };
  },
});

/**
 * 树的图标设置
 * @author  韦胜健
 * @date    2024.9.5 21:43
 */
export const NodeIconMap: Record<string, string | undefined> = {
  string: 'ri-font-family',
  number: 'ri-hashtag',
  boolean: 'ri-check-double-line',
  date: 'ri-calendar-line',
  datetime: 'ri-calendar-schedule-line',

  entity: 'ri-braces-line',
  empty: 'ri-info-i',
  generality: 'ri-text',
  unknown: 'ri-question-mark',
};

/**
 * 基础类型
 * @author  韦胜健
 * @date    2024.9.22 17:00
 */
export const BasicEntities: iEntity[] = [
  { id: 'string', code: 'string', isBasic: true, title: '字符串', seq: 0 },
  { id: 'number', code: 'number', isBasic: true, title: '数字', seq: 0 },
  { id: 'boolean', code: 'boolean', isBasic: true, title: '布尔值', seq: 0 },
  { id: 'date', code: 'date', isBasic: true, title: '日期', seq: 0 },
  { id: 'datetime', code: 'datetime', isBasic: true, title: '日期时间', seq: 0 },
  { id: 'Array', code: 'Array', title: '数组', seq: 0, generalityConfigJson: '[{"title":"元素泛型","code":"T"}]', fieldConfigJson: '[{"title":"数组长度","code":"length","entityCode":{"sec":"number"}}]' },
  { id: 'Query', code: 'Query', title: '接口', seq: 0 },
];

// 注册基础类型
BasicEntities.forEach(i => {i.isInternal = true;});

export const EntityCodeSelector = designComponent({
  name: 'entity-code-selector',
  props: {
    label: { type: String, required: true },
    hideLabel: { type: Boolean, },
    modelValue: { type: Object as PropType<iEntityFieldItem['entityCode']> },
    parseEntities: { type: Array as PropType<iParseEntity[]>, required: true },
  },
  emits: {
    onUpdateModelValue: (val?: iEntityFieldItem['entityCode']) => true,
  },
  setup({ props, event: { emit } }) {

    const model = useModel(() => props.modelValue, emit.onUpdateModelValue);

    const classes = useClassCache(() => [
      getComponentCls('entity-code-selector')
    ]);

    const currentParseEntity = computed((): undefined | iParseEntity => {
      if (!model.value?.sec) {return undefined;}
      return props.parseEntities.find(i => i.code === model.value!.sec);
    });

    const handler = {
      onSelectChange: (val: any) => {
        const parseEntity = props.parseEntities.find(i => i.code === val);
        model.value = { sec: val, ...parseEntity?.generalityConfig.length ? { gcs: {} } : {} };
      },
      validateValueGetter: () => model.value?.sec
    };

    return () => (
      <>
        <FormItem hideLabel className={classes.value} required validateValueGetter={handler.validateValueGetter} label={props.label}>
          <Select
            modelValue={model.value?.sec}
            onUpdateModelValue={handler.onSelectChange}
            inputSlots={props.hideLabel ? undefined : { prefix: () => <span key="prefix">{props.label}</span> }}
          >
            {props.parseEntities.map(item => (
              <SelectOption label={item.title} val={item.code} key={item.code}/>
            ))}
          </Select>
        </FormItem>
        <div className={getComponentCls("sub-entity-code-selector-list")}>
          {!!currentParseEntity.value?.generalityConfig.length && (
            currentParseEntity.value?.generalityConfig.map(genItem => (
              <EntityCodeSelector
                key={genItem.code}
                label={genItem.title}
                v-model={model.value!.gcs![genItem.code]}
                parseEntities={props.parseEntities}
              />
            ))
          )}
        </div>
      </>
    );
  },
});
